package shs

import (
	"iter"
	"unsafe"

	"github.com/cespare/xxhash"
	"github.com/cockroachdb/swiss"
)

type Index interface {
	Get(key []byte) (uint64, error)
	Set(key []byte, value uint64) error
	Delete(key []byte) error
	Iterator() iter.Seq2[[]byte, uint64]
}

var _ Index = (*DefaultIndex)(nil)

type DefaultIndex struct {
	inner *swiss.Map[string, uint64]
}

func NewDefaultIndex() *DefaultIndex {
	return &DefaultIndex{
		inner: swiss.New(0, swiss.WithHash[string, uint64](func(key *string, seed uintptr) uintptr {
			res := xxhash.Sum64String(*key)
			return uintptr(res)
		})),
	}
}

func stringToBytes(s string) []byte {
	return unsafe.Slice(unsafe.StringData(s), len(s))
}

func bytesToString(b []byte) string {
	return unsafe.String(&b[0], len(b))
}

func (d *DefaultIndex) Iterator() iter.Seq2[[]byte, uint64] {
	return func(yield func([]byte, uint64) bool) {
		d.inner.All(func(k string, v uint64) bool {
			keyBytes := stringToBytes(k)
			return yield(keyBytes, v)
		})
	}
}

func (d *DefaultIndex) Get(key []byte) (uint64, error) {
	u, exists := d.inner.Get(bytesToString(key))
	if !exists {
		return 0, ErrKeyNotFound
	}
	return u, nil
}

func (d *DefaultIndex) Set(key []byte, value uint64) error {
	d.inner.Put(bytesToString(key), value)
	return nil
}

func (d *DefaultIndex) Delete(key []byte) error {
	d.inner.Delete(bytesToString(key))
	return nil
}
